/*
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007  MontaVista Software, Inc.
* Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
*/
#include "test/globaldef.h"
#include "test/m_penuLoad.h"

enum SPI_CTRL_CMD
{
  SPI_SET_kHZ = 10,
  SPI_SET_CPOL,
  SPI_SET_CPHA,
  SPI_SET_DELAY,
  NFPGA_RST,
  NDSP_RST,
  FPGA_RTRIG,
  SPI_CLK,
  IRQ_TURN,
  SPI_SET_WR
};

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static const char *SPI_device = "/dev/spi_ww";
static const char *DSP_code   = "Download/DetDSP";
static const char *FPGA_code  = "Download/DetFPGA";
static int m_SPI_fd = 0;
static uint8_t mode = 0;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;

static void pabort(const char *s)
{
  perror(s);
  abort();
}

static void print_usage(const char *prog)
{
  mLog("Usage: %s [-DsbdlHOLC3]\n", prog);
  puts("  -D --device   device to use (default /dev/spidev1.1)\n"
    "  -s --speed    max speed (Hz)\n"
    "  -d --delay    delay (usec)\n"
    "  -b --bpw      bits per word \n"
    "  -l --loop     loopback\n"
    "  -H --cpha     clock phase\n"
    "  -O --cpol     clock polarity\n"
    "  -L --lsb      least significant bit first\n"
    "  -C --cs-high  chip select active high\n"
    "  -3 --3wire    SI/SO signals shared\n");
  exit(1);
}

static void parse_opts(int argc, char *argv[])
{
  while (1) {
    static const struct option lopts[] = {
      { "device",  1, 0, 'D' },
      { "speed",   1, 0, 's' },
      { "delay",   1, 0, 'd' },
      { "bpw",     1, 0, 'b' },
      { "loop",    0, 0, 'l' },
      { "cpha",    0, 0, 'H' },
      { "cpol",    0, 0, 'O' },
      { "lsb",     0, 0, 'L' },
      { "cs-high", 0, 0, 'C' },
      { "3wire",   0, 0, '3' },
      { "no-cs",   0, 0, 'N' },
      { "ready",   0, 0, 'R' },
      { NULL, 0, 0, 0 },
    };
    int c;

    c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);

    if (c == -1)
      break;

    switch (c) {
    case 'D':
      SPI_device = optarg;
      break;
    case 's':
      speed = atoi(optarg);
      break;
    case 'd':
      delay = atoi(optarg);
      break;
    case 'b':
      bits = atoi(optarg);
      break;
    case 'l':
      mode |= SPI_LOOP;
      break;
    case 'H':
      mode |= SPI_CPHA;
      break;
    case 'O':
      mode |= SPI_CPOL;
      break;
    case 'L':
      mode |= SPI_LSB_FIRST;
      break;
    case 'C':
      mode |= SPI_CS_HIGH;
      break;
    case '3':
      mode |= SPI_3WIRE;
      break;
    case 'N':
      mode |= SPI_NO_CS;
      break;
    case 'R':
      mode |= SPI_READY;
      break;
    default:
      print_usage(argv[0]);
      break;
    }
  }
}
int is_open = 0;
is_my_SPI_open()
{
  return is_open;
}
void my_SPI_Init()
{
  char* para[]={"mySPI",
    "-D",   "/dev/spi_ww",   //the device file
    "-s",   "268288",           //the speed of transfer(Hz)
    "-d",   "6",                //the delay between bytes
    "-b",   "8",                //the bits per word
    "-H",   "-O",               //no loop, write on rising clock,MSB, -C,-3,-N,-R is not used for dm365
  };
  parse_opts(5, para);  //parse the options

  int ret = 0;
  m_SPI_fd = open(SPI_device, O_RDWR);
  if (m_SPI_fd < 0)
    pabort("can't open SPI device");
  is_open = 1;
  ret = ioctl(m_SPI_fd, 1, 1);
  ret = ioctl(m_SPI_fd, 2, mode & SPI_CPHA);

  ret = ioctl(m_SPI_fd,SPI_SET_kHZ,speed/1000);
  if (ret == -1)
    pabort("can't set max speed hz");

  mLog("spi mode: %x\n", mode);
  mLog("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
}
void my_SPI_DeInit()
{
  close(m_SPI_fd);
  is_open = 0;
}
void my_SPI_Load_pneuDSP()
{
  int ret;
  int rc = 1;
  unsigned int i=1;
  unsigned char send_buf[16];
  unsigned char recv_buf[16] = {0, };
  printf("loading pneuDSP......\n");

  ioctl(m_SPI_fd, SPI_SET_DELAY, 6);// 6uS delay between bytes 
  ioctl(m_SPI_fd, SPI_SET_CPHA, 1);
  ioctl(m_SPI_fd, SPI_SET_CPOL, 1);
  /*----------- Reset the pneumatic DSP in case of warm start.----------------- */
  ioctl(m_SPI_fd, NDSP_RST, 0);

  /* send out one byte! */
  send_buf[0] = PneuDSP_Start[0];

  ret = write(m_SPI_fd,send_buf,rc);

  if (ret != 0)
    pabort("can't send spi message to EPC");

  /* --------------------Release the DSP reset. --------------------------------*/
  ioctl(m_SPI_fd, NDSP_RST, 1);
  usleep(1);
  
  /* sending the balance:
  delay=6us between byte transfers.  This time allows the DSP to swallow the byte before the next one is shifted out to the
  pneumatics board. 
  */
//  while( (rc = fread(send_buf,sizeof(unsigned char), 16,infile)) > 0 )

  ret = write(m_SPI_fd,PneuDSP_Start+1,PneuDSP_codeNum-1);
/*
  for(i=1; i<PneuDSP_codeNum;i++)
  {
    send_buf[0] = PneuDSP_Start[i];
    ret = write(m_SPI_fd,send_buf,rc);
    if (ret != 0)
      pabort("can't send spi message to EPC");
  }
*/
  /* Need > 8 dummy clocks to clear the bus request on the DSP,here send 16 bits, 16 dummy clocks */
//  send_buf[0] = 0;
//  send_buf[1] = 0;
//  ret = write(m_SPI_fd,send_buf,2);
  for (i = 0; i < 9; i++)
  {
      ioctl(m_SPI_fd, SPI_CLK, 0);           /* Send the SCK low */
      ioctl(m_SPI_fd, SPI_CLK, 1);           /* Send the SCK high */
  }
  if (ret != 0)
    pabort("can't send spi message to EPC");

  printf("finished loading pneuDSP......\n");
}
int my_SPI_Load_pneuFPGA()
{
  int ret;
  unsigned int i=0;
  unsigned char send_buf[16];
  unsigned char recv_buf[16] = {0, };
  int rc = 1;

  printf("loading pneuFPGA......\n");

  ioctl(m_SPI_fd, SPI_SET_DELAY, 2);// 2uS delay between bytes
  ioctl(m_SPI_fd, SPI_SET_CPHA, 1);
  ioctl(m_SPI_fd, SPI_SET_CPOL, 1);

  /*----------- Reset the pneumatic FPGA in case of warm start.----------------- */
  ioctl(m_SPI_fd, NFPGA_RST, 0);
  usleep(5000); //Delay loop (~ 5 mSec)
  /* --------------------Release the FPGA reset. --------------------------------*/
  ioctl(m_SPI_fd, NFPGA_RST, 1);
  usleep(50000); //Delay loop (~ 50 mSec)

//  while( (rc = fread(send_buf,sizeof(unsigned char), 16,infile)) > 0 )

  ret = write(m_SPI_fd,PneuFPGA_Start,PneuFPGA_codeNum);
  usleep(1);
/*
  for(i=0;i <PneuFPGA_codeNum; i++)
  {
    send_buf[0] = PneuFPGA_Start[i];
    ret = write(m_SPI_fd,send_buf,rc);
    if (ret != 0)
      pabort("can't send spi message to EPC");
  }
*/


  /* Need > 8 dummy clocks to clear the bus request on the DSP,here send 16 bits, 16 dummy clocks */
//  send_buf[0] = 0;
//  send_buf[1] = 0;
//  ret = write(m_SPI_fd,send_buf,2);
  if (ret != 0)
    pabort("can't send spi message to EPC");

  printf("finished loading pneuFPGA......\n");
  return 0;
}
void InitializeOnchipQSM()
{
  ioctl(m_SPI_fd,SPI_SET_kHZ,500);  //500kHz, the 68331 is 4Mhz,but gpio_spi highest Hz is 500k 
  ioctl(m_SPI_fd, SPI_SET_DELAY, 3);// 1uS delay between bytes 
  ioctl(m_SPI_fd, SPI_SET_CPOL, 1);
  ioctl(m_SPI_fd, SPI_SET_CPHA, 0);
}
void my_SPI_write(char* buffer, size_t length)
{
  int i=0;
  char sendb[32];
  unsigned short *pWord;
  if(length == 32) // send the cmd to EPC
  {
    memcpy(sendb,buffer,32);
/*
pWord = (unsigned short*)sendb;
if(pWord[0] > 0x0c)
{
  printf("write cmd:");
  for(i=0;i<16;i++)
  {
    printf("%04x  ",pWord[i]);
  }
  printf("\n");
}
*/
    for(i=0;i<16;i++)  //change little-endian to big-endian
    {
      char temp = sendb[i*2];
      sendb[i*2] = sendb[i*2+1];
      sendb[i*2+1] = temp;
    }

    write(m_SPI_fd,sendb,length);
  }
  else
    write(m_SPI_fd,buffer,length);
}
void my_SPI_read(char* buffer, size_t length)
{
  read(m_SPI_fd,buffer,length);
  int i=0;
  unsigned short *pWord;
  if(length == 32) // recv the resp from EPC
  {
    for(i=0;i<16;i++)  //change big-endian to little-endian
    {
      char temp = buffer[i*2];
      buffer[i*2] = buffer[i*2+1];
      buffer[i*2+1] = temp;
    }
  }
/*
  pWord = (unsigned short*)buffer;
  if(length == 32 && pWord[0] > 0x0c )
  {
    printf("send :");
    for(i=0;i<16;i++)
    {
      printf("%04x  ",pWord[i]);
    }
    printf("\n");
  }
*/
}

void my_SPI_setWR(unsigned char WRflag)
{
  ioctl(m_SPI_fd, SPI_SET_WR, WRflag);
}

